package com.soft.mainsite.module.staticstrategy.staticservice;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Maps;
import com.soft.mainsite.common.constant.CmsConst;
import com.soft.mainsite.common.domain.ErrorCode;
import com.soft.mainsite.common.utils.JsonUtil;
import com.soft.mainsite.common.utils.SpringBeanUtil;
import com.soft.mainsite.component.beetl.html.BeetlHtmlUtil;
import com.soft.mainsite.module.publishlog.service.PublishLogService;
import com.soft.mainsite.module.sitecode.entity.SiteCode;
import com.soft.mainsite.module.sitecode.service.SiteCodeService;
import com.soft.mainsite.module.staticstrategy.entity.TemplateManage;
import com.soft.mainsite.module.staticstrategy.exception.HtmlStaticException;
import com.soft.mainsite.module.staticstrategy.service.TemplateManagerService;
import com.soft.mainsite.module.web.cms.service.CategoryService;
import com.soft.mainsite.module.web.cms.service.ContentService;
import com.soft.mainsite.module.web.cms.service.ModelService;
import com.soft.mainsite.module.web.cms.service.SiteService;
import com.soft.mainsite.mybatis.mapper.TCmsContentMapper;
import com.soft.mainsite.mybatis.model.TCmsCategory;
import com.soft.mainsite.mybatis.model.TCmsModel;
import com.soft.mainsite.mybatis.model.TCmsSite;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * 页面静态化接口实现
 *
 * @author liupengtao
 * @date 2019/04/29
 */
@Slf4j
@Service
public class StaticHtmlServiceImpl implements StaticHtmlService {


    @Autowired
    private HttpServletRequest request;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private SiteService siteService;

    @Autowired
    private TCmsContentMapper contentMapper;

    @Autowired
    private ModelService modelService;

    @Autowired
    private PublishLogService publishLogService;

    @Autowired
    private TemplateManagerService templateManagerService;

    @Autowired
    private SiteCodeService siteCodeService;

    @Autowired
    private BeetlHtmlUtil beetlHtmlUtil;

    @Autowired
    private ContentStaticService contentStaticService;


    @Value("${system.site.static.path}")
    String staticPath;

    @Value("${system.site.static.site.path}")
    String sitePath;

    @Value("${system.site.subfix}")
    private String siteSubfix;

    /**
     * 网站首页静态化方法
     *
     * @param siteId  站点id
     * @param tplType 模板类型
     */
    @Override
    public String index(Integer siteId, String tplType) throws Exception {

        if (CmsConst.MAIN_SITE_ID.equals(siteId)) {
            this.initCommonPage(siteId, tplType);
        }

        TCmsSite site = siteService.findById(siteId);
        Map<String, Object> siteInfo = builderSiteInfo(site, null, null);

        //获取模板根路径
        String tplPath = CmsConst.TPL_TYPE_MOBILE.equals(tplType) ? CmsConst.MOBILE_PATH : CmsConst.WEB_PATH;

        try {
            beetlHtmlUtil.create(request, siteId, CmsConst.SUFFIX_INDEX, siteInfo, tplPath, CmsConst.INDEX_TPL, false,tplType);
            return JsonUtil.toSuccess();
        } catch (Exception e) {
            publishLogService.save(siteId, null, CmsConst.SUFFIX_INDEX, ErrorCode.E_100112.getCode());
            log.error("首页静态化失败，站点id:{}", siteId, e);
            throw e;
        }
    }

    @Override
    public String forward(Integer siteId, String type) throws Exception {

        TCmsSite site = siteService.findById(siteId);

        //获取模板根路径
        String tplPath = CmsConst.TPL_TYPE_MOBILE.equals(type) ? CmsConst.MOBILE_PATH : CmsConst.WEB_PATH;
        Map<String, Object> siteInfo = builderSiteInfo(site, null, null);

        try {
            beetlHtmlUtil.create(request, siteId, CmsConst.FORWARD, siteInfo, tplPath, CmsConst.FORWARD, false,type);
            return JsonUtil.toSuccess();
        } catch (Exception e) {
            log.error("转发页静态化失败，站点id:{}", siteId, e);
            publishLogService.save(siteId, null, CmsConst.FORWARD, ErrorCode.E_100111.getCode());
            throw e;
        }
    }

    @Override
    public String common(Integer siteId, String tplName, String tplType) throws Exception {
        TemplateManage templateManage = templateManagerService.querfyTemplateManageByName(tplName);

        //获取模板根路径
        String tplPath = CmsConst.TPL_TYPE_MOBILE.equals(tplType) ? CmsConst.MOBILE_PATH : CmsConst.WEB_PATH;
        String renderName = templateManage.getRenderTemplateName();

        try {
            beetlHtmlUtil.createCommonList(request, null, tplName, "", tplPath, renderName,tplType);
            triggerStatic(siteId, null, null, CmsConst.TPL_TYPE_MOBILE, false);
            return JsonUtil.toSuccess("静态化成功");
        } catch (Exception e) {
            publishLogService.save(siteId, null, tplName, ErrorCode.E_100116.getCode());
            log.error("单页静态失败，站点id:{} 模板:{}", siteId, tplName, e);
            throw e;
        }
    }

    /**
     * 栏目首页静态化方法
     *
     * @param siteId     站点id
     * @param categoryId 栏目id
     * @param tplType    模板类型
     */
    @Override
    public String category(Integer siteId, Long categoryId, String tplType) throws Exception {

        TCmsCategory category = categoryService.findById(categoryId);

        TCmsSite site = siteService.findById(siteId);
        Map<String, Object> siteInfo = builderSiteInfo(site, category, null);

        //获取模板根路径
        String tplPath = CmsConst.TPL_TYPE_MOBILE.equals(tplType) ? CmsConst.MOBILE_PATH : CmsConst.WEB_PATH;
        String action = category.getAlias();

        //模板名称
        String tplIndexName = StrUtil.isBlank(category.getIndexTpl()) ? CmsConst.CATEGORY_INDEX_TPL : category.getIndexTpl();
        String tplListName = StrUtil.isBlank(category.getListTpl()) ? CmsConst.CATEGORY_LIST_TPL : category.getListTpl();


        //栏目是否含有列表页
        boolean isPageList = tplIndexName.equals(tplListName);

        //静态化首页
        try {
            //跳過默认栏目首页静态页面
            if (!CmsConst.CATEGORY_INDEX_TPL.equals(tplIndexName)) {
                beetlHtmlUtil.create(request, siteId, action, siteInfo, tplPath, tplIndexName, false,tplType);
            }
        } catch (Exception e) {
            publishLogService.save(siteId, categoryId, tplIndexName, ErrorCode.E_100113.getCode());
            log.error("栏目首页静态化失败,站点id:{}栏目id:{}", siteId, categoryId, e);
            throw e;
        }

        //静态化列表页
        if (!isPageList) {
            try {
                //跳過默认栏目列表页静态页面
                if (!CmsConst.CATEGORY_LIST_TPL.equals(tplListName)) {
                    beetlHtmlUtil.create(request, siteId, action + "_list", siteInfo, tplPath, tplListName, false,tplType);
                }
            } catch (Exception e) {
                publishLogService.save(siteId, categoryId, tplListName, ErrorCode.E_100126.getCode());
                log.error("栏目列表页静态化失败,站点id:{}栏目id:{}", siteId, categoryId, e);
            }
        }

        return JsonUtil.toSuccess("静态化成功");
    }


    /**
     * 栏目内容静态化
     *
     * @param siteId 站点id
     * @param categoryId 栏目id
     * @param contentId 内容id
     * @param tplType 模板类型
     */
    @Override
    public String content(Integer siteId, Long categoryId, Long contentId, String tplType, boolean isPub) throws Exception {
        TCmsSite site = siteService.findById(siteId);
        TCmsCategory category = categoryService.findById(categoryId);
        TCmsModel contentModel = modelService.findById(category.getModelId());
        Map content = contentMapper.selectByContentIdAndTableName(contentId, contentModel.getTableName());

        Map<String, Object> siteInfo = builderSiteInfo(site, category, content);

        //获取模板根路径
        String tplPath = CmsConst.TPL_TYPE_MOBILE.equals(tplType) ? CmsConst.MOBILE_PATH : CmsConst.WEB_PATH;

        //模板名称
        String tplName = StrUtil.isBlank(category.getContentTpl()) ? CmsConst.CONTENT_TPL : category.getContentTpl();
        String action = category.getAlias() + File.separator + contentId;

        if (category.getAlone()) {
            action = category.getAlias() + File.separator + tplName;
        }

        try {
            beetlHtmlUtil.create(request, siteId, action, siteInfo, tplPath, tplName, isPub,tplType);
            return JsonUtil.toSuccess();
        } catch (Exception e) {
            publishLogService.save(siteId, categoryId, tplName, ErrorCode.E_100114.getCode());
            log.error("静态化内容页失败,站点id{}栏目id{}内容id{}", siteId, categoryId, contentId, e);
            throw e;
        }
    }

    /**
     * 公共栏目列表静态化
     *
     * @param siteId 站点id
     * @param categoryId 栏目id
     * @param contentId 内容id
     * @param type 模板类型
     */
    @Override
    public String commonListStatic(Integer siteId, Long categoryId, Long contentId, String type) throws Exception {
        TCmsCategory category = categoryService.findById(categoryId);

        if (category == null || StrUtil.isBlank(category.getIndexTpl())) {
            return JsonUtil.toError(ErrorCode.E_100122.getCode());
        }

        //获取被关联模板名称
        String templates = "";
        if (CmsConst.CATEGORY_INDEX_TPL.equals(category.getIndexTpl())) {
            if (CmsConst.CATEGORY_LIST_TPL.equals(category.getListTpl())) {
                templates = category.getContentTpl();
            } else {
                templates = category.getListTpl();
            }
        } else {
            templates = category.getIndexTpl();
        }

        //根据栏目模板查询所有关联的公共栏目列表模板
        List<TemplateManage> templateManageChildList = templateManagerService.queryRelationManageByParnetTemplate(templates);

        if (CollectionUtil.isEmpty(templateManageChildList)) {
            return JsonUtil.toError(ErrorCode.E_100119.getCode());
        }

        //获取模板根路径
        String tplPath = CmsConst.TPL_TYPE_MOBILE.equals(type) ? CmsConst.MOBILE_PATH : CmsConst.WEB_PATH;
        for (TemplateManage item : templateManageChildList) {
            String tplName = item.getTemplateName();
            String renderName = item.getRenderTemplateName();

            List<SiteCode> siteTypeList = siteCodeService.listByPid(CmsConst.SITE_TYPE_ID);

            //遍历站点类型，更新所有类型代码片段
            siteTypeList.forEach(siteTypeItem -> {
                try {
                    beetlHtmlUtil.createCommonList(request, categoryId, tplName, siteTypeItem.getCode(), tplPath, renderName,type);
                } catch (Exception e) {
                    publishLogService.save(siteId, categoryId, tplName, ErrorCode.E_100115.getCode());
                    log.error("公共栏目列表静态化失败,主模板{}", category.getIndexTpl(), e);
                    throw e;
                }
            });
        }

        return JsonUtil.toError(ErrorCode.E_100115.getCode());
    }

    @Override
    public void initCommonPage(Integer siteId, String type) throws Exception {
        initCommonSinglePage(siteId, type);
        initSinglePage(siteId,type);
        initCommonFragent(siteId, type);
    }

    /**
     * 初始化公共单页
     * @param siteId 站点id
     * @param type 模板类型
     * @throws Exception
     */
    private void initCommonSinglePage(Integer siteId, String type) throws Exception{
        List<TemplateManage> templateList = templateManagerService.queryCommonSingleTemplateManage(CmsConst.SINGLE_STATIC);

        if (CollectionUtil.isNotEmpty(templateList) && templateList.size() > 0) {
            templateList.removeAll(Collections.singleton(null));
        }
        //获取模板根路径
        String tplPath = CmsConst.TPL_TYPE_MOBILE.equals(type) ? CmsConst.MOBILE_PATH : CmsConst.WEB_PATH;

        for (TemplateManage templateManage : templateList) {
            String tplName = templateManage.getTemplateName();
            String renderName = templateManage.getRenderTemplateName();
            try {
                beetlHtmlUtil.createCommonList(request, null, tplName, "", tplPath, renderName,type);
            } catch (Exception e) {
                publishLogService.save(siteId, null, tplName, ErrorCode.E_100116.getCode());
                log.error("初始化公共栏目单页静态失败，模板{}", tplName, e);
                throw e;
            }
        }
    }

    /**
     * 初始化公共代码片段
     *
     * @param siteId 站点id
     * @param type 模板类型
     */
    @Override
    public void initCommonFragent(Integer siteId, String type) throws Exception {
        List<TCmsCategory> categoryList = categoryService.findAllCategoryTplBySiteId(siteId);
        List<SiteCode> siteTypeList = siteCodeService.listByPid(CmsConst.SITE_TYPE_ID);
        for (TCmsCategory category : categoryList) {
            String tplPath = CmsConst.TPL_TYPE_MOBILE.equals(type) ? CmsConst.MOBILE_PATH : CmsConst.WEB_PATH;
            //模板名称
            String tplIndexName = StrUtil.isBlank(category.getIndexTpl()) ? CmsConst.CATEGORY_INDEX_TPL : category.getIndexTpl();
            if (!CmsConst.CATEGORY_INDEX_TPL.equals(category.getIndexTpl())){
                staticFragmentByTplName(siteId, siteTypeList, category, tplPath, tplIndexName,type);
            }
            String tplListName = StrUtil.isBlank(category.getListTpl()) ? CmsConst.CATEGORY_LIST_TPL : category.getListTpl();
            if(!CmsConst.CATEGORY_LIST_TPL.equals(category.getListTpl())){
                staticFragmentByTplName(siteId, siteTypeList, category, tplPath, tplListName,type);
            }
            String tplContentName = StrUtil.isBlank(category.getContentTpl()) ? CmsConst.CONTENT_TPL : category.getContentTpl();
            if(!CmsConst.CONTENT_TPL.equals(category.getContentTpl())){
                staticFragmentByTplName(siteId, siteTypeList, category, tplPath, tplContentName,type);
            }
        }

    }

    private void staticFragmentByTplName(Integer siteId, List<SiteCode> siteTypeList, TCmsCategory category, String tplPath, String tplListName,String type) throws Exception{
        //获取模板关联的代码公共片段
        List<TemplateManage> templateList = templateManagerService.queryRelationManageByParnetTemplate(tplListName);
        if (CollectionUtil.isNotEmpty(templateList) && templateList.size() > 0) {
            templateList.removeAll(Collections.singleton(null));
        }
        templateList.forEach(templateManage -> {
            //公共路径按照站点类型渲染
            String tplName = templateManage.getTemplateName();
            String renderName = templateManage.getRenderTemplateName();
            siteTypeList.forEach(siteType -> {
                try {
                    beetlHtmlUtil.createCommonList(request, category.getCategoryId(), tplName, siteType.getCode(), tplPath, renderName,type);
                } catch (Exception e) {
                    publishLogService.save(siteId, null, tplName, ErrorCode.E_100116.getCode());
                    log.error("初始化公共栏目列表静态失败，模板{}", tplName, e);
                    throw e;
                }
            });
        });
    }

    /**
     * 仅静态化私有单页，检索页
     * @param siteId 站点id
     * @param tplType 模板类型
     * @throws Exception
     */
    @Override
    public void initSinglePage(Integer siteId, String tplType) throws Exception {

        TCmsSite site = siteService.findById(siteId);
        Map<String, Object> siteInfo = builderSiteInfo(site, null, null);

        List<TemplateManage> templateList = templateManagerService.querySingleTemplateManage(CmsConst.SINGLE_STATIC);

        if (CollectionUtil.isNotEmpty(templateList) && templateList.size() > 0) {
            templateList.removeAll(Collections.singleton(null));
        }

        //获取模板根路径
        String tplPath = CmsConst.TPL_TYPE_MOBILE.equals(tplType) ? CmsConst.MOBILE_PATH : CmsConst.WEB_PATH;

        for (TemplateManage templateManage : templateList) {
            String tplName = templateManage.getTemplateName();
            String renderName = templateManage.getRenderTemplateName();

            try {
                beetlHtmlUtil.create(request, siteId, tplName, siteInfo, tplPath, renderName, false,tplType);
            } catch (Exception e) {
                publishLogService.save(siteId, null, tplName, ErrorCode.E_100116.getCode());
                log.error("初始化单页静态失败，站点id:{} 模板:{}", siteId, tplName, e);
                throw e;
            }
        }

    }

    /**
     * 触发关联页面静态化
     *
     * @param siteId 站点id
     * @param categoryId 栏目id
     * @param contentId 内容id
     * @param type 模板类型
     * @param isPub 是否公共
     */
    @Override
    public void triggerStatic(Integer siteId, Long categoryId, Long contentId, String type, boolean isPub) throws Exception {

        TCmsCategory category = categoryService.findById(categoryId);

        if (category == null || StrUtil.isBlank(category.getIndexTpl())) {
            return;
        }

        //获取被关联模板名称
        String templates = "";
        if (CmsConst.CATEGORY_INDEX_TPL.equals(category.getIndexTpl())) {
            if (CmsConst.CATEGORY_LIST_TPL.equals(category.getListTpl())) {
                templates = category.getContentTpl();
            } else {
                templates = category.getListTpl();
            }
        } else {
            templates = category.getIndexTpl();
        }

        List<TemplateManage> templateManageList = templateManagerService.queryTriggerManageByParnetTemplate(templates);
        if (CollectionUtil.isEmpty(templateManageList)) {
            return;
        }

        TCmsSite site = siteService.findById(siteId);
        //获取模板根路径
        String tplPath = CmsConst.TPL_TYPE_MOBILE.equals(type) ? CmsConst.MOBILE_PATH : CmsConst.WEB_PATH;

        TCmsModel contentModel = modelService.findById(category.getModelId());
        Map content = contentMapper.selectByContentIdAndTableName(contentId, contentModel.getTableName());
        Map<String, Object> siteInfo = builderSiteInfo(site, category, content);

        for (TemplateManage templateManage : templateManageList) {
            String tplName = Convert.toStr(templateManage.getTemplateName());
            String action = "";
            if (StrUtil.contains(tplName, '/')) {
                action = StrUtil.subAfter(tplName, "/", true);
            } else {
                action = tplName;
            }
            try {
                beetlHtmlUtil.create(request, siteId, action, siteInfo, tplPath, tplName, false,type);
            } catch (Exception e) {
                publishLogService.save(siteId, categoryId, tplName, ErrorCode.E_100117.getCode());
                log.error("关联页面静态化失败,模板{}", tplName, e);
                throw e;
            }
        }
    }

    /**
     * 根据模板名称触发静态化
     *
     * @param siteId 站点id
     * @param tplName 模板名称
     * @param type 模板类型
     * @param isPub 是否公共
     * @throws HtmlStaticException
     */
    @Override
    public void triggerStatic(Integer siteId, String tplName, String type, boolean isPub) throws Exception {
        List<TemplateManage> templateManageList = templateManagerService.queryTriggerManageByParnetTemplate(tplName);
        if (CollectionUtil.isEmpty(templateManageList)) {
            return;
        }
        //获取模板根路径
        String tplPath = CmsConst.TPL_TYPE_MOBILE.equals(type) ? CmsConst.MOBILE_PATH : CmsConst.WEB_PATH;
        TCmsSite site = siteService.findById(siteId);

        Map<String, Object> siteInfo = builderSiteInfo(site, null, null);

        for (TemplateManage templateManage : templateManageList) {
            String templateName = Convert.toStr(templateManage.getTemplateName());
            String renderName = Convert.toStr(templateManage.getRenderTemplateName());

            if (StrUtil.contains(templateName, '/')) {
                templateName = StrUtil.subAfter(templateName, "/", true);
            }

            try {

                if (isPub) {
                    beetlHtmlUtil.createCommonList(request, null, templateName, "", tplPath, renderName,type);
                } else {
                    beetlHtmlUtil.create(request, siteId, templateName, siteInfo, tplPath, renderName, false,type);
                }

            } catch (Exception e) {
                publishLogService.save(siteId, null, tplName, ErrorCode.E_100127.getCode());
                log.error("触发页面静态化失败,模板:{}", templateName, e);
                throw e;
            }
        }
    }


    /**
     * 删除内容同步删除静态化内容
     *
     * @param ids 站点id
     */
    @Transactional(transactionManager = "masterTransactionManager", rollbackFor = Exception.class)
    @Override
    public void clearStaticHtml(Long[] ids) throws Exception {

        if (ArrayUtil.isEmpty(ids)) {
            return;
        }

        ContentService contentService = SpringBeanUtil.getBean(ContentService.class);

        for (Long contentId : ids) {

            Map map = contentMapper.selectByContentId(contentId);
            if (MapUtil.isEmpty(map)) {
                continue;
            }

            contentService.deleteContent(new Long[]{contentId});

            TCmsSite site = siteService.findById(MapUtil.getInt(map, "siteId"));
            TCmsCategory category = categoryService.findById(MapUtil.getLong(map, "categoryId"));

            String alias = category.getAlias();
            //是否是主站发布公共栏目
            boolean isPub = category.getIsCommon() && CmsConst.MAIN_SITE_ID.equals(site.getSiteId());
            StringBuilder filePath = new StringBuilder();
            if (isPub) {
                //主站发布公共栏目内容存放路径
                filePath.append(staticPath)
                        .append(File.separator)
                        .append("common/content")
                        .append(File.separator)
                        .append(CmsConst.TPL_TYPE_MOBILE)
                        .append(File.separator)
                        .append(alias)
                        .append(File.separator)
                        .append(contentId)
                        .append(siteSubfix)
                        .toString();
            } else {
                //子站发布内容存放路径
                filePath.append(staticPath)
                        .append(File.separator)
                        .append(sitePath)
                        .append(File.separator)
                        .append(site.getSiteKey())
                        .append(File.separator)
                        .append(CmsConst.TPL_TYPE_MOBILE)
                        .append(File.separator)
                        .append(alias)
                        .append(File.separator)
                        .append(contentId)
                        .append(siteSubfix)
                        .toString();
            }

            File file = new File(filePath.toString());

            try {
                //先重新静态化页面 在删除内容详情页面
                contentStaticService.contentStatic(site.getSiteId(), category.getCategoryId(), contentId, CmsConst.TPL_TYPE_MOBILE, CmsConst.DEL_STATIC);
                FileUtil.del(file);
            } catch (Exception e) {
                publishLogService.save(site.getSiteId(), category.getCategoryId(), alias + contentId + ".html", ErrorCode.E_100118.getCode());
                log.error("删除静态化败，内容id:{}", contentId, e);
                throw e;
            }

        }
    }


    /**
     * 构建站点静态化公用基础信息
     *
     * @param site 站点信息
     * @param category 栏目信息
     * @return Map集合
     */
    private Map<String, Object> builderSiteInfo(TCmsSite site, TCmsCategory category, Map<String, Object> content) {
        Map<String, Object> attr = Maps.newHashMap();

        attr.put("keyword", site.getKeyword());
        attr.put("description", site.getDescription());
        attr.put("site", site);

        if (category != null) {
            attr.put("title", category.getCategoryName());
            attr.put("category", category);
        }

        if (MapUtil.isNotEmpty(content)) {
            attr.put("content", content);
        }

        return attr;
    }


}
